#include "Network.h"

// =====================================================================
//      PUBLIC
// =====================================================================

Network::~Network()
{
    _quit_update_loop_mutex.Acquire();
    _quit_update_loop=true;
    _quit_update_loop_mutex.Release();
    
    pthread_join(thread,NULL);
    
    close(_sock_fd);
}

bool Network::Send(int target_sockfd, NetworkMessage* msg)
{
    ApplicationLog::Print("Network::Send to ",target_sockfd,ApplicationLog::DEBUG);
    
    int n = send(target_sockfd,msg->GetData(),msg->GetLength(),0);
    
    if (n<0)
        return false;
}

Event<int, NetworkMessage*>& Network::OnNewMessage()
{
    return _new_message_event;
}

// =====================================================================
//      PROTECTED
// =====================================================================

bool Network::Initialize()
{
    _quit_update_loop=false;
    
    int ret = pthread_create(&thread,NULL,&Network::Wrapper,this);

    if (ret!=0)
        return false;
    
    return true;
}

void Network::HandleNewData(int target_sockfd)
{
    ApplicationLog::Print("Network::HandleNewData",ApplicationLog::DEBUG);
    
    uint8 header_data[NetworkMessage::GetHeaderLength()];
    int r = recv(target_sockfd,header_data,NetworkMessage::GetHeaderLength(),0);
    
    if ( r < NetworkMessage::GetHeaderLength() )
    {
        ApplicationLog::Print("Network::HandleNewData - Error reading msg header",ApplicationLog::ERROR);
        LostConnectionHandler(target_sockfd);
    }
    else
    {
        NetworkMessage* new_msg = new NetworkMessage(header_data);
        
        r = recv(target_sockfd,new_msg->GetBody(),new_msg->GetBodyLength(),0);
        
        if ( r < new_msg->GetBodyLength() )
        {
            ApplicationLog::Print("Network::HandleNewData - Error reading msg body",ApplicationLog::ERROR);
            LostConnectionHandler(target_sockfd);
        }
        else
        {
            ApplicationLog::Print("Network::HandleNewData - reading msg body",ApplicationLog::INFO);
            printf("recieved Message from sock: ",target_sockfd);

            _new_message_event.Notify(target_sockfd,new_msg);
        }
    }
}

void Network::QuitMainLoop()
{
    _quit_update_loop_mutex.Acquire();
    _quit_update_loop=true;
    _quit_update_loop_mutex.Release();
}

// =====================================================================
//      PRIVATE
// =====================================================================

void Network::Update()
{
    // Limpio el set
    FD_ZERO(&ready);

    PrepareSet();

    timeval timeout;
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;
    
    int active_socks = select(maxsock, &ready, NULL, NULL, &timeout);
    
    if(active_socks < 0)
    {
        ApplicationLog::Print("Network::Update - Error, active_socks < 0, exiting update loop.",ApplicationLog::FATAL);
        
        QuitMainLoop();
    }
    
    else if(active_socks == 0) ; // Nothing new

    else HandleActiveSockets();
}

void Network::MainLoop()
{
    ApplicationLog::Print("Network::MainLoop - Initializing main loop\n",ApplicationLog::DEBUG);
    
    bool quit = false;
    while(!quit)
    {
        Update();
        
        _quit_update_loop_mutex.Acquire();
        quit = _quit_update_loop;
        _quit_update_loop_mutex.Release();
    }
    
    ApplicationLog::Print("Network::MainLoop - Terminating main loop\n",ApplicationLog::DEBUG);
}

void* Network::Wrapper(void* arg)
{
    Network* instance = (Network*)arg;
    instance->MainLoop();
}

